// PgPlotter.cpp - MARIN MSG Anneke Sicherer-Roetman 20080609

#include <string.h>
#include <stdio.h>
#include "PgPlotter.h"
#include "assertplus.h"

typedef char * STRING;

static void pgplot_ini(float *f, int mxi, int mxj, float fmin, float fmax, const char *strtim);
static void pgend();
static void pgplot_nxt(float *f, int mxi, int mxj, float fmin, float fmax, const char *strold, const char *strnew);
static void fiddle();

// plotting through fortran library pgplot:
#define Fplot_ref(a, b) m_Fplot[(b - 1) * m_xmax + a - 1]

/// constructor
PgPlotter::PgPlotter(int xmin, int ymin, int xmax, int ymax, const Array2D<float> &plot, const std::string &caption, float fmin, float fmax)
    : base(xmin, ymin, xmax, ymax, plot, caption)
    , m_Fplot(new float[xmax * ymax])
    , m_Fmin(fmin)
    , m_Fmax(fmax)
{
    ASSERT(xmin == 1, "pgplot requires lower boundary to be 1");
    ASSERT(ymin == 1, "pgplot requires lower boundary to be 1");
    for (int i2 = ymin; i2 <= ymax; ++i2)
    {
        for (int i1 = xmin; i1 <= xmax; ++i1)
        {
            Fplot_ref(i1, i2) = plot[i1][i2];
        }
    }
    pgplot_ini(m_Fplot, m_xmax, m_ymax, m_Fmin, m_Fmax, m_caption.c_str());
    m_previousCaption = m_caption;
}
   
/// destructor
PgPlotter::~PgPlotter()
{
    pgend();
    delete m_Fplot;
}

/// plots new data
void PgPlotter::plot()
{
    for (int i2 = m_ymin; i2 <= m_ymax; ++i2)
    {
        for (int i1 = m_xmin; i1 <= m_xmax; ++i1)
        {
            Fplot_ref(i1, i2) = m_data[i1][i2];
        }
    }
    pgplot_nxt(m_Fplot, m_xmax, m_ymax, m_Fmin, m_Fmax, m_previousCaption.c_str(), m_caption.c_str());
    m_previousCaption = m_caption;
}

/// keeps plotter running at end of simulation
void PgPlotter::run()
{
    fiddle();
}

#define max(a,b)  ((a)>(b)?(a):(b))
#define min(a,b)  ((a)<(b)?(a):(b))

extern "C"
{
extern int pgbox_(char *, float *, int *, char *, float *, int *, short, short);
extern int pgctab_(float *, float *, float *, float *, int *, float *, float *);
extern int pgcurs_(float *, float *, char *, short);
extern int pgimag_(float *, int *, int *, int *, int *, int *, int *, float *, float *, float *);
extern int pgmtxt_(char *, float *, float *, float *, char *, short, short);
extern int pgopen_(char *, short);
extern int pgpage_(void);
extern int pgqcir_(int *, int *);
extern int pgqinf_(char *, char *, int *, short, short);
extern int pgqvp_(int *, float *, float *, float *, float *);
extern int pgqwin_(float *, float *, float *, float *);
extern int pgsch_(float *);
extern int pgsci_(int *);
extern int pgsvp_(float *, float *, float *, float *);
extern int pgswin_(float *, float *, float *, float *);
extern int pgvsiz_(float *, float *, float *, float *);
extern int pgwedg_(char *, float *, float *, float *, float *, char *, short, short);
extern int pgwnad_(float *, float *, float *, float *);
extern void pgend_(void);
}

/* Table of constant values */

static float zero = 0.0;
static float one  = 1.0;

static int c__0 = 0;
static int c__1 = 1;
static int c__2 = 2;
static int c__5 = 5;
static int c__9 = 9;
static int c__10 = 10;
static int c__20 = 20;

static void setvp(void)
{
    /* Local variables */
    float d__, vpx1, vpx2, vpy1, vpy2;

    /* Set the viewport, allowing margins around the edge for annotation. */
    /* (This is similar in effect to PGVSTD, but has different margins.) */
    /* The routine determines the view-surface size and allocates margins */
    /* as fractions of the minimum of width and height. */
    pgsvp_(&zero, &one, &zero, &one);
    pgqvp_(&c__1, &vpx1, &vpx2, &vpy1, &vpy2);
    d__ = min(vpx2 - vpx1, vpy2 - vpy1) / 40.0;
    vpx1 += d__ * 5.0;
    vpx2 -= d__ * 2.0;
    vpy1 += d__ * 8.0;
    vpy2 -= d__ * 2.0;
    pgvsiz_(&vpx1, &vpx2, &vpy1, &vpy2);
} /* setvp_ */


static void palett(int type, float contra, float bright)
{
    /* Initialized data */
    static float gl[2]  = { 0.0,1.0 };
    static float gr[2]  = { 0.0,1.0 };
    static float gg[2]  = { 0.0,1.0 };
    static float gb[2]  = { 0.0,1.0 };
    static float rl[9]  = { -.5,0.0,.17,.33,.5,.67,.83,1.0,1.7 };
    static float rr[9]  = { 0.0,0.0,0.0,0.0,.6,1.0,1.0,1.0,1.0 };
    static float rg[9]  = { 0.0,0.0,0.0,1.0,1.0,1.0,.6,0.0,1.0 };
    static float rb[9]  = { 0.0,.3,.8,1.0,.3,0.0,0.0,0.0,1.0 };
    static float hl[5]  = { 0.0,.2,.4,.6,1.0 };
    static float hr[5]  = { 0.0,.5,1.0,1.0,1.0 };
    static float hg[5]  = { 0.0,0.0,.5,1.0,1.0 };
    static float hb[5]  = { 0.0,0.0,0.0,.3,1.0 };
    static float wl[10] = { 0.0,.5,.5,.7,.7,.85,.85,.95,.95,1.0 };
    static float wr[10] = { 0.0,1.0,0.0,0.0,.3,.8,.3,1.0,1.0,1.0 };
    static float wg[10] = { 0.0,.5,.4,1.0,0.0,0.0,.2,.7,1.0,1.0 };
    static float wb[10] = { 0.0,0.0,0.0,0.0,.4,1.0,0.0,0.0,.95,1.0 };
    static float al[20] = { 0.0,.1,.1,.2,.2,.3,.3,.4,.4,.5,.5,.6,
                	    .6,.7,.7,.8,.8,.9,.9,1.0 };
    static float ar[20] = { 0.0,0.0,.3,.3,.5,.5,0.0,0.0,0.0,0.0,0.0,0.0,
                     	    0.0,0.0,1.0,1.0,1.0,1.0,1.0,1.0 };
    static float ag[20] = { 0.0,0.0,.3,.3,0.0,0.0,0.0,0.0,.8,.8,.6,.6,
                     	    1.0,1.0,1.0,1.0,.8,.8,0.0,0.0 };
    static float ab[20] = { 0.0,0.0,.3,.3,.7,.7,.7,.7,.9,.9,0.0,0.0,
                     	    0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 };

    /* Set a "palette" of colors in the range of color indices used by PGIMAG. */
    if (type == 1) 
    {
        /* gray scale */
	pgctab_(gl, gr, gg, gb, &c__2, &contra, &bright);
    } 
    else if (type == 2) 
    {
        /* rainbow */
	pgctab_(rl, rr, rg, rb, &c__9, &contra, &bright);
    } 
    else if (type == 3) 
    {
        /* heat */
	pgctab_(hl, hr, hg, hb, &c__5, &contra, &bright);
    } 
    else if (type == 4) 
    {
        /* weird IRAF */
	pgctab_(wl, wr, wg, wb, &c__10, &contra, &bright);
    } 
    else if (type == 5) 
    {
        /* AIPS */
	pgctab_(al, ar, ag, ab, &c__20, &contra, &bright);
    }
} /* palett_ */


static void pgplot_ini(float *f, int mxi, int mxj, float fmin, float fmax, const char *strtim)
{
    static float c_b28 = 0.6;
    static float c_b36 = 3.0;
    static float c_b41 = 4.0;
    static float c_b42 = 5.0;

    /* System generated locals */
    int f_dim1, f_offset;
    float r__1, r__2;

    /* Local variables */
    int l, c1, c2, nc;
    float tr[6];
    char val[16];
    float bright;
    float contra;

    /* Parameter adjustments */
    f_dim1 = mxi;
    f_offset = 1 + f_dim1;
    f -= f_offset;

    /* Function Body */
    
    /* Open device for graphics. */
    if (pgopen_(STRING("/xwin"), (short)5) < 1) 
    {
        ASSERT(false, "pgplot device not opened");
    }
    pgqinf_(STRING("TYPE"), val, &l, (short)4, (short)16);
    pgqcir_(&c1, &c2);
    nc = max(0, c2 - c1 + 1);
    ASSERT(nc >= 8, "not enough colors available on this device");

    /* Set the coordinate transformation matrix: world coordinate = pixel number. */
    tr[0] = 0.0;
    tr[1] = 1.0;
    tr[2] = 0.0;
    tr[3] = 0.0;
    tr[4] = 0.0;
    tr[5] = 1.0;

    /* Clear the screen. Set up window and viewport. */
    pgpage_();
    setvp();
    r__1 = mxi + 1.0;
    r__2 = mxj + 1.0;
    pgwnad_(&zero, &r__1, &zero, &r__2);

    /* Set up the color map. */
    bright = .5;
    contra = 1.0;
    palett(c__2, contra, bright);

    /* Draw the map with PGIMAG. */
    pgimag_(&f[f_offset], &mxi, &mxj, &c__1, &mxi, &c__1, &mxj, &fmin, &fmax, tr);

    /* Annotate the plot. */
    pgmtxt_(STRING("t"), &one, &zero, &zero, (char*)strtim, (short)1, strlen(strtim));
    pgsch_(&c_b28);
    pgbox_(STRING("bcntsi"), &zero, &c__0, STRING("bcntsiv"), &zero, &c__0, (short)6, (
	    short)7);
    pgmtxt_(STRING("b"), &c_b36, &one, &one, STRING("pixel number"), (short)1, (short)
	    12);

    /* Draw a wedge. */  
    pgwedg_(STRING("BI"), &c_b41, &c_b42, &fmin, &fmax, STRING("pixel value"), (short)2, (short)11);
    pgsch_(&one);
} /* pgplot_ini__ */


static void pgplot_nxt(float *f, int mxi, int mxj, float fmin, float fmax, const char *strold, const char *strnew)
{
    /* System generated locals */
    int f_dim1, f_offset;

    /* Local variables */
    float tr[6];

    /* Parameter adjustments */
    f_dim1 = mxi;
    f_offset = 1 + f_dim1;
    f -= f_offset;

    /* Function Body */
    
    /* Set the coordinate transformation matrix: world coordinate = pixel number. */
    tr[0] = 0.0;
    tr[1] = 1.0;
    tr[2] = 0.0;
    tr[3] = 0.0;
    tr[4] = 0.0;
    tr[5] = 1.0;
    pgimag_(&f[f_offset], &mxi, &mxj, &c__1, &mxi, &c__1, &mxj, &fmin, &fmax, tr);
    pgsci_(&c__0);
    pgmtxt_(STRING("t"), &one, &zero, &zero, (char*)strold, (short)1, strlen(strold));
    pgsci_(&c__1);
    pgmtxt_(STRING("t"), &one, &zero, &zero, (char*)strnew, (short)1, strlen(strnew));
} /* pgplot_nxt__ */

static void pgend(void)
{
    pgend_();
}

static void fiddle(void)
{
    /* Local variables */
    int p;
    float x, y, b1, b2, c1, c2, x1, y1, x2, y2;
    char ch[1];
    int ier;
    float sign, bright, contra;

    printf("Use cursor to adjust color table:\n");
    printf(" Keys 1,2,3,4,5 select different palettes\n");
    printf(" Key P cycles through available palettes\n");
    printf(" Key F adjusts contrast and brightness, with\n");
    printf("  cursor x position setting brightness [0.0 - 1.0]\n");
    printf("   and y position setting contrast [0.0 - 10.0]\n");
    printf("  (Hold down F key while moving cursor to change\n");
    printf("  contrast and brightness continuously)\n");
    printf(" Key C resets contrast=1.0, brightness=0.5\n");
    printf(" Key - reverses color palette\n");
    printf(" Key X or right mouse button exits program\n");

    p = 2;
    contra = 1.0;
    bright = .5;
    x = .5;
    y = 1.0;
    sign = 1.0;

    pgqwin_(&x1, &x2, &y1, &y2);
    b1 = 0.0;
    b2 = 1.0;
    c1 = 0.0;
    c2 = 10.0;
    pgswin_(&b1, &b2, &c1, &c2);
L10:
    ier = pgcurs_(&x, &y, ch, (short)1);
    if (*(unsigned char *)ch == '\0' || *(unsigned char *)ch == 'x' || *(unsigned char *)ch == 'X') 
    {
	pgswin_(&x1, &x2, &y1, &y2);
	return;
    } 
    else if (*(unsigned char *)ch == 'F' || *(unsigned char *)ch == 'f') 
    {
        bright = max(b1, min(b2,x));
        contra = max(c1, min(c2,y));
    } 
    else if (*(unsigned char *)ch == 'C' || *(unsigned char *)ch == 'c') 
    {
	contra = 1.0;
	y = 1.0;
	bright = .5;
	x = .5;
    } 
    else if (*(unsigned char *)ch == '-') 
    {
	sign = -sign;
    } 
    else if (*(unsigned char *)ch == '1') 
    {
	p = 1;
    } 
    else if (*(unsigned char *)ch == '2') 
    {
	p = 2;
    } 
    else if (*(unsigned char *)ch == '3') 
    {
	p = 3;
    } 
    else if (*(unsigned char *)ch == '4') 
    {
	p = 4;
    } 
    else if (*(unsigned char *)ch == '5') 
    {
	p = 5;
    } 
    else if (*(unsigned char *)ch == 'P' || *(unsigned char *)ch == 'p') 
    {
	p = p % 5 + 1;
    }
    palett(p, sign * contra, bright);
    goto L10;
}

